package cn.org.gs.buffer;

import org.junit.Test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class BufferDemo2 {
    @Test
    public void buffer01() {
        // 数据字缓冲区分片,在现有的缓冲区基础上切片生成一个新的缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(10);

        for (int i = 0; i < buffer.capacity(); i ++) {
            buffer.put((byte)i);
        }

        buffer.position(3);
        buffer.limit(7);
        ByteBuffer slice = buffer.slice();

        for (int i = 0; i < slice.capacity(); i ++) {
            byte b = slice.get(i);
            slice.put(i, (byte) (b * 10));
        }

        buffer.position(0);
        buffer.limit(buffer.capacity());
        while (buffer.remaining() > 0) {
            System.out.print(buffer.get() + " ");
        }
    }

    @Test
    public void testBuffer02() {
        // 只读缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(10);

        for (int i = 0; i < buffer.capacity(); i ++) {
            buffer.put((byte) i);
        }

        ByteBuffer onlyBuffer = buffer.asReadOnlyBuffer();

        for (int i = 0; i < buffer.capacity(); i ++) {
            byte b = buffer.get(i);
            buffer.put(i, (byte) (b + 1)); // 赋值时可能会出现异溢出错误，所有最好加上下标对缓冲区进行赋值
        }

        onlyBuffer.position(0);
        onlyBuffer.limit(buffer.capacity());

        while (onlyBuffer.remaining() > 0) {
            System.out.print(onlyBuffer.get() + " ");
        }
        System.out.println();

    }

    // 直接缓冲区，加快IO操作，它会在每一次调用底层操作系统的本机 I/O 操作之前(或之后)，
    //尝试避免将缓冲区的内容拷贝到一个中间缓冲区中 或者从一个中间缓冲区中拷贝数
    //据。要分配直接缓冲区，需要调用 allocateDirect()方法，而不是 allocate()方法，使
    //用方式与普通缓冲区并无区别。
    @Test
    public void testBuffer03() throws Exception{
        String inFile = "d:\\1.txt";
        FileInputStream fin = new FileInputStream(inFile);
        FileChannel fcin = fin.getChannel();

        String outFile = "d:\\03.txt";
        FileOutputStream fout = new FileOutputStream(outFile);
        FileChannel fcout = fout.getChannel();

        ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

        while (true){
            buffer.clear();
            int r = fcin.read(buffer);
            if(r == -1) {
                break;
            }
            buffer.flip();
            fcout.write(buffer);
        }

        fin.close();
        fcout.close();
    }

    static private final int start = 0;
    static private final int end = 1024;
    // 内存映射文件IO，比常规的基宇流或者通道的IO快的多,只有文件中实际读取或者写入的部分才会映射到内存中
    @Test
    public void testBuffer04() throws Exception{
        RandomAccessFile aFile = new RandomAccessFile("d:\\1.txt", "rw");
        FileChannel channel = aFile.getChannel();

        MappedByteBuffer mbb = channel.map(FileChannel.MapMode.READ_WRITE, start, end);

        mbb.put(0, (byte) 97);
        mbb.put(1023, (byte) 122);

        aFile.close();

    }
}
